#include "stm32f10x.h"
#include "Delay.h"
#include <stdio.h>

void USART1_TxRx_Init(void);			// 初始化USART1引脚与输出模式
void USART1_Init(void);					// 初始化USART1数据传输格式
void USART1_IRQHandler(void);			// 初始化USART1数据接收方式
void USART1_NVIC_Init(void);			// 配置USART1外设的中断源, 以及初始化NVIC外设
void GPIO_InitLED(void);				// 初始化LED引脚与输出模式
void GPIO_ControlLED(uint8_t byteRcvd); // 初始化LED控制方式

// 全局变量
volatile uint8_t new_data_flag = 0;  // 标记是否收到新数据
volatile uint8_t last_char = 0;      // 记录上次接收的字符

int main(void) {
	USART1_TxRx_Init();  // 初始化 USART1 的 TX/RX 引脚
    USART1_Init();       // 初始化 USART1
	GPIO_InitLED();	     // 初始化 LED
	USART1_NVIC_Init();	 // 配置USART1外设的中断源, 以及初始化NVIC外设
	
    while (1) {		 	 // 主循环保持空闲或执行其他任务
        // 如果有新数据，立即更新LED状态
        if (new_data_flag) {
            new_data_flag = 0;
            GPIO_ControlLED(last_char);
        }
	}
}

/**
 * @brief  配置 USART1 的 TX（PA9）和 RX（PA10）引脚
 * @param  无
 * @retval 无
 */
void USART1_TxRx_Init(void) {
    // 开启 GPIOA 时钟
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE); 

    // 配置 PA9（USART1 TX）：说明书指定USART1输出引脚
    GPIO_InitTypeDef GPIO_InitStruct;				// 定义结构体
    GPIO_InitStruct.GPIO_Pin = GPIO_Pin_9; 			// 结构体引脚：9
    GPIO_InitStruct.GPIO_Mode = GPIO_Mode_AF_PP;    // 结构体模式：【复用】推挽输出模式，需要单片机而非GPIOA模块进行操作
    GPIO_InitStruct.GPIO_Speed = GPIO_Speed_2MHz;   // 结构体速度：引脚输出速度可以选择2MHz,对于串口通信的慢速率来说（115200）,2MHz足矣
    GPIO_Init(GPIOA, &GPIO_InitStruct); 			// 初始化结构体

    // 配置 PA10（USART1 RX）：说明书指定USART1输入引脚
    GPIO_InitStruct.GPIO_Pin = GPIO_Pin_10;  		  	 // 结构体引脚：9
    GPIO_InitStruct.GPIO_Mode = GPIO_Mode_IN_FLOATING;   // 浮空输入模式：适合具有稳定输入的引脚，此处也可替换为上拉输入
    GPIO_Init(GPIOA, &GPIO_InitStruct);  				 // 初始化结构体
}

/**
  * @brief   初始化USAR1外设,数据位是8位,不带校验位,停止位是1位,波特率是115200
  * @param   无
  * @retval  无
  */
void USART1_Init(void) {
    // 1.开启USART1外设时钟
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1, ENABLE);

    // 2.利用USART_Init函数完成USART1外设的初始化
    USART_InitTypeDef USART_InitStruct;												// 定义结构体
    USART_InitStruct.USART_BaudRate = 115200;   									// 波特率设置为115200
    USART_InitStruct.USART_HardwareFlowControl = USART_HardwareFlowControl_None;    // 不使用硬件流控
    USART_InitStruct.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;    // 设置为可收可发模式
    USART_InitStruct.USART_Parity = USART_Parity_No;    			// 不进行数据校验
    USART_InitStruct.USART_StopBits = USART_StopBits_1;     		// 选择1位停止位
    USART_InitStruct.USART_WordLength = USART_WordLength_8b;  	    // 数据位是8位
    USART_Init(USART1, &USART_InitStruct);  					    // 初始化结构体

    // 3.使能开启USART1外设
    USART_Cmd(USART1, ENABLE);		// 开启USART总开关
}


/**
 * @brief  轮询方式接收1个字符
 * @param  无
 * @retval 接收到的数据
 * @note   
 */
void USART1_IRQHandler(void) {
    if (USART_GetITStatus(USART1, USART_IT_RXNE) != RESET){   	// 等待接收寄存器数据发送完毕，即状态更换为SET后退出
		last_char = (uint8_t)USART_ReceiveData(USART1);   	  	// 接收1个字节的数据								  // 自定义缓冲区函数
		new_data_flag = 1;                     					// 标记有新数据
		USART_ClearITPendingBit(USART1, USART_IT_RXNE);			// 标志位由硬件自动清除
	
        GPIO_ControlLED(last_char);								// 立即执行一次控制（确保实时性）
	}
}


/**
 * @brief  配置USART1外设的中断源, 以及初始化NVIC外设
 * @param  无
 * @retval 无
 * @note   
 */
void USART1_NVIC_Init(void){
	USART_ITConfig(USART1, USART_IT_RXNE, ENABLE);  // 使能接收中断
	NVIC_EnableIRQ(USART1_IRQn);                    // 使能USART1全局中断
    
	NVIC_InitTypeDef NVIC_InitStruct;
    NVIC_InitStruct.NVIC_IRQChannel = USART1_IRQn;
    NVIC_InitStruct.NVIC_IRQChannelPreemptionPriority = 0;  // 抢占优先级
    NVIC_InitStruct.NVIC_IRQChannelSubPriority = 0;          // 子优先级
    NVIC_InitStruct.NVIC_IRQChannelCmd = ENABLE;
    NVIC_Init(&NVIC_InitStruct);
	
	NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);  // 2位抢占优先级，2位子优先级
}

/**
  * @brief 初始化LED
  * @param  无
  * @retval  无
  * @note   LED阳极接入PA0,阴极接入负极,设置引脚为通用推挽输出模式
  */
void GPIO_InitLED(void) {
    // 1.开启GPIOA的外设时钟
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);

    // 2.初始化PA0引脚, 设置为通用推挽输出
    GPIO_InitTypeDef GPIO_InitStruct;

    GPIO_InitStruct.GPIO_Pin = GPIO_Pin_0;  		// 初始化PA0引脚
    GPIO_InitStruct.GPIO_Speed = GPIO_Speed_2MHz;   // 引脚输出速度为2MHz
    GPIO_InitStruct.GPIO_Mode = GPIO_Mode_Out_PP;   // 引脚设置为通用推挽输出
    GPIO_Init(GPIOA, &GPIO_InitStruct);
	
	// 3.初始状态熄灭LED
	GPIO_ResetBits(GPIOA, GPIO_Pin_0);
}

/**
 * @brief  通过 USART1 发送字节数组到PC
 * @param  Datas  指向待发送数据的字节数组
 * @param  Length  需要发送的字节数，也就是字节数组的长度
 * @retval Delay_Ms 是一个阻塞式的延时函数，会导致中断服务程序（ISR）长时间占用 CPU，影响其他任务的执行
 */
void GPIO_ControlLED(uint8_t byteRcvd) {
    switch(byteRcvd){
		// LED 灭
		case '0':
			GPIO_ResetBits(GPIOA, GPIO_Pin_0);
			break;
		// LED 亮
		case '1':
			GPIO_SetBits(GPIOA, GPIO_Pin_0);
			break;
		// LED 快闪
		case '2':
            while(1){
				GPIO_SetBits(GPIOA, GPIO_Pin_0);
				Delay_Ms(100);
				GPIO_ResetBits(GPIOA, GPIO_Pin_0);
				Delay_Ms(100);
                if (USART_GetFlagStatus(USART1, USART_FLAG_RXNE) != RESET) 
                    return; // 如果收到新数据，立即退出
            }
			break;
		// LED 慢闪
		case '3':
            while(1){
				GPIO_SetBits(GPIOA, GPIO_Pin_0);
				Delay_Ms(500);
				GPIO_ResetBits(GPIOA, GPIO_Pin_0);
				Delay_Ms(500);
                if (USART_GetFlagStatus(USART1, USART_FLAG_RXNE) != RESET) 
                    return; // 如果收到新数据，立即退出
            }
			break;
		default:
			break;
	}
}
